Skip to content

fix(snmp): walk only what the switch can safely answer - #26

Merged
Gerrrt merged 1 commit into
mainfrom
fix/mokerlink-ifspecific
Aug 19, 2026
Merged

fix(snmp): walk only what the switch can safely answer#26
Gerrrt merged 1 commit into
mainfrom
fix/mokerlink-ifspecific

Conversation

@Gerrrt

@Gerrrt Gerrrt commented Aug 19, 2026

Copy link
Copy Markdown
Owner

Makes neo produce metrics for the first time. Deployed and confirmed.

What changed

The mokerlink walk goes from the whole ifTable (1.3.6.1.2.1.2.2) to the five
columns anything actually consumes: ifIndex, ifDescr, ifOperStatus,
ifInOctets, ifOutOctets.

Why

Two independent faults were stacked, which is why every single-cause fix
appeared to do nothing.

1. No firewall rule. Nothing permitted 10.0.99.20 → 10.7.7.2 on UDP/161,
so polls were dropped before arriving. Fixed on pfSense, outside this repo.

2. A malformed varbind. The switch returns ifSpecific (ifTable column 22)
with a zero-length value:

.1.3.6.1.2.1.2.2.1.22.26=

An OBJECT IDENTIFIER cannot be zero-length, so snmp-exporter rejects the whole
GETBULK response:

error in unmarshalResponse: error decoding value: error parsing OID Value: invalid OID length

One bad varbind cost all 22 metrics.

Listing columns 1-21 does not fix it — that was tried and failed. GETBULK
returns the next N varbinds and does not stop at a subtree boundary, so walking
.21 overshoots into .22 and the bad varbind comes back anyway. The last
column walked must be far enough from .22 that max_repetitions cannot reach
it. overrides: ifSpecific: ignore does not help either: it drops the metric
from the config, but the reply still has to be decoded.

Walking less is also the conservative choice on its own merits. This switch was
bricked once by a full walk and has wedged since, so scrape volume is a safety
property here rather than an efficiency one.

Blast radius

snmp-exporter's mokerlink module only. The other three modules are
byte-identical.

  • No change to network segmentation or firewall rules
  • No new port published to a VLAN that could not already reach the service
  • No credential added outside secrets/*.sops.yaml

Deliberately drops 16 metrics (1791 → 1775), so make snmp-generate warns
about metric loss — that warning is expected here. Dropped: ifType, ifMtu,
ifSpeed, ifPhysAddress, ifAdminStatus, ifLastChange, ifInUcastPkts,
ifInNUcastPkts, ifInDiscards, ifInErrors, ifInUnknownProtos,
ifOutUcastPkts, ifOutNUcastPkts, ifOutDiscards, ifOutErrors,
ifOutQLen. None is referenced by any rule or dashboard (verified by grep over
prometheus/rules/ and grafana/dashboards/).

Verification

Deployed via make render && make reload.

up{job="snmp"}
  neo       10.7.7.2     up=1     <- was 0 for every scrape ever recorded
  morpheus  10.0.99.1    up=1
  mjolnir   10.0.99.10   up=1
  shiva     10.0.30.10   up=1

Metrics arriving — 26 ports, 19 up:

ifDescr x26   ifIndex x26   ifOperStatus x26   ifInOctets x26   ifOutOctets x26

Scrape cost, which is the number that matters for this device:

snmp_scrape_packets_sent     30
snmp_scrape_packets_retried  0
snmp_scrape_pdus_returned    130
scrape_duration_seconds      1.42

No exporter errors since the reload. SnmpTargetUnreachable and InstanceDown
for 10.7.7.2 have cleared.

  • make validate passes
  • Deployed to the lab and confirmed working
  • Docs updated (rationale is in generator.yaml, beside the walk list)

Known limitation

./scripts/snmp-verify.sh still reports FAIL for neo. It probes
sysDescr.0 with a single GET, and this switch does not answer ad-hoc probes
reliably even while serving the exporter's scrape cleanly at 0 retries — it
appears to throttle or accept only one SNMP conversation at a time. Not
investigated further on purpose, because characterising it means sending this
switch more SNMP than it has proven able to take.

The exporter scraping successfully is itself proof the community is correct, so
the rotation is verified by a different route. Filed separately rather than
worked around here.

Closes #22

neo has never produced a metric. Two faults sat on top of each other, and
fixing either alone changed nothing observable.

The first was a missing pfSense rule: nothing permitted 10.0.99.20 to reach
10.7.7.2 on UDP/161, so every poll was dropped before it arrived. Fixed on the
firewall, not here.

The second is this. The switch returns ifSpecific (ifTable column 22) with a
zero-length value:

    .1.3.6.1.2.1.2.2.1.22.26=

An OBJECT IDENTIFIER cannot be zero-length, so snmp-exporter rejects the entire
GETBULK response with "error parsing OID Value: invalid OID length" and the
scrape yields nothing. One malformed varbind cost all 22 metrics.

Listing columns 1-21 does not fix it. GETBULK returns the next N varbinds and
does not stop at a subtree boundary, so walking .21 overshoots into .22 and the
bad varbind comes back regardless. The last column walked has to be far enough
from .22 that max_repetitions cannot reach it.

So the walk is now the five columns something actually consumes — ifIndex,
ifDescr, ifOperStatus, ifInOctets, ifOutOctets. That is also the conservative
choice on its own merits: this switch was bricked once by a full walk and has
wedged since, so scrape volume is a safety property here. Measured cost is now
30 packets and 130 PDUs per scrape, 0 retries, 1.4s.

Drops 16 metrics (1791 -> 1775) deliberately: ifType, ifMtu, ifSpeed,
ifPhysAddress, ifAdminStatus, ifLastChange and the error/discard counters. None
is referenced by any rule or dashboard. Adding one back is a line, but anything
past .16 has to be checked against the ifSpecific overshoot first.

neo now scrapes clean: 26 ports, 19 up, all four SNMP targets up.

Closes #22

Co-Authored-By: Claude Opus 5 <[email protected]>
@Gerrrt
Gerrrt merged commit 197d739 into main Aug 19, 2026
3 checks passed
@Gerrrt
Gerrrt deleted the fix/mokerlink-ifspecific branch August 19, 2026 02:45
Gerrrt added a commit that referenced this pull request Aug 19, 2026
fix(snmp): walk only what the switch can safely answer
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

neo (MokerLink, 10.7.7.2) stopped answering SNMP — ICMP and TCP/80 succeed, UDP/161 does not

1 participant